Skip to content

fix: visualizer getCSV method throwing constant errors#1263

Open
HardeepAsrani wants to merge 1 commit intodevelopmentfrom
fix/issue-400
Open

fix: visualizer getCSV method throwing constant errors#1263
HardeepAsrani wants to merge 1 commit intodevelopmentfrom
fix/issue-400

Conversation

@HardeepAsrani
Copy link
Member

Summary

Adds safeguards to prevent the _getCSV from throwing constant errors.

Will affect visual aspect of the product

YES/NO

Screenshots

Test instructions

  • Not sure how we can test, we have just added safe guards to prevent it from happening.

Check before Pull Request is ready:

Closes https://github.com/Codeinwp/visualizer-pro/issues/400.

@HardeepAsrani HardeepAsrani requested a review from Copilot March 5, 2026 22:19
@pirate-bot pirate-bot added the pr-checklist-complete The Pull Request checklist is complete. (automatic label) label Mar 5, 2026
@pirate-bot
Copy link
Contributor

Plugin build for 3c603d5 is ready 🛎️!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to stop Visualizer’s CSV export (_getCSV) from repeatedly triggering runtime errors by adding additional safeguards around temporary file creation, and updates the test suite/tooling to support newer PHPUnit behavior.

Changes:

  • Add a fallback/early-return guard in Visualizer_Module::_getCSV() when a writable temp file handle can’t be created.
  • Refactor/export tests to reuse a helper for running the export AJAX action and add CSV response-structure assertions.
  • Add Yoast PHPUnit Polyfills (and bootstrap loading) to improve PHPUnit cross-version compatibility; update composer.lock accordingly.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
classes/Visualizer/Module.php Adds additional guard(s) when temp file creation fails during CSV generation.
tests/test-export.php Adds a helper to run export AJAX, adds CSV structure test, adjusts invalid-chart expectations.
tests/test-ajax.php Replaces deprecated PHPUnit assertions with property_exists() checks.
tests/bootstrap.php Loads Yoast PHPUnit Polyfills autoloader early in the test bootstrap.
composer.json Adds yoast/phpunit-polyfills to require-dev.
composer.lock Locks new dev dependencies brought in by PHPUnit polyfills/tooling changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

$fp = fopen( wp_tempnam(), 'w+' );
}
if ( ! $fp ) {
return array( 'csv' => '', 'name' => $filename, 'string' => '' );
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_getCSV() now returns a non-empty array even when it cannot obtain a writable temp file handle. Because callers (e.g. the AJAX export handler) typically treat any non-empty return value as success, this can result in success: true responses with an empty CSV payload, which is misleading and makes failures harder to detect. Consider returning null/false on file-handle failure (or including an explicit error indicator) so the export endpoint can fail gracefully (e.g. send a JSON error) instead of reporting success with empty data.

Suggested change
return array( 'csv' => '', 'name' => $filename, 'string' => '' );
return null;

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, do we have a handler that works with an empty string property? Or they just download an empty file?

Comment on lines +61 to +86
/**
* Runs the export AJAX action and returns the decoded response.
*
* @since 3.11.0
*
* @access private
* @return object
*/
private function run_export() {
$_GET = array(
'security' => wp_create_nonce( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION ),
'chart' => $this->chart,
);

ob_start();
try {
$this->_handleAjax( 'visualizer-export-data' );
} catch ( WPAjaxDieContinueException $e ) {
// We expected this, do nothing.
} catch ( WPAjaxDieStopException $ee ) {
// We expected this, do nothing.
}
ob_end_clean();

return json_decode( $this->_last_response );
}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run_export() docblock says @return object, but json_decode() can return null on empty/invalid JSON. Updating the return type doc (and/or adding an assertion that $this->_last_response is non-empty) will make the helper’s contract accurate and prevent confusing failures when the AJAX handler emits no JSON.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good observation.

$this->create_chart();
$this->_setRole( 'administrator' );

$response = $this->run_export();
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_csv_export_response_structure() dereferences $response->success without first asserting that $response is an object. If the AJAX handler returns no output (e.g. due to an environment issue), this will error out with a PHP fatal instead of producing a clear assertion failure. Consider adding assertIsObject( $response ) (and optionally property_exists) before using $response->success.

Suggested change
$response = $this->run_export();
$response = $this->run_export();
$this->assertIsObject( $response );
$this->assertTrue( property_exists( $response, 'success' ) );
$this->assertTrue( property_exists( $response, 'data' ) );

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@Soare-Robert-Daniel Soare-Robert-Daniel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Copilot made some great points on the review.

Comment on lines +61 to +86
/**
* Runs the export AJAX action and returns the decoded response.
*
* @since 3.11.0
*
* @access private
* @return object
*/
private function run_export() {
$_GET = array(
'security' => wp_create_nonce( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION ),
'chart' => $this->chart,
);

ob_start();
try {
$this->_handleAjax( 'visualizer-export-data' );
} catch ( WPAjaxDieContinueException $e ) {
// We expected this, do nothing.
} catch ( WPAjaxDieStopException $ee ) {
// We expected this, do nothing.
}
ob_end_clean();

return json_decode( $this->_last_response );
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good observation.

$fp = fopen( wp_tempnam(), 'w+' );
}
if ( ! $fp ) {
return array( 'csv' => '', 'name' => $filename, 'string' => '' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, do we have a handler that works with an empty string property? Or they just download an empty file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-complete The Pull Request checklist is complete. (automatic label)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants